//
//  DownloadManager.swift
//  ImGuider X
//
//  Created by llt on 2018/9/14.
//  Copyright © 2018年 imguider. All rights reserved.
//

import UIKit
import Tiercel

typealias ProgressBlock = (_ complete:Bool,_ success:Bool,_ progress: Double) -> Void

class DownloadManager: NSObject {
    
    
    /// 单例对象
    static let share = DownloadManager()
    
    private var managers:[String:TRManager]
    
    private let picManager = TRManager("picture", MaximumRunning: 9, isStoreInfo: true)
    
    
    private override init() {
        
        managers = [:]
    }
    
    private func loadManager(lineid:String) -> TRManager {
        
        var manager:TRManager
        
        if managers.keys.contains(lineid) {
            
            manager = managers[lineid]!
        } else {
            
            manager = TRManager(lineid, MaximumRunning: 3, isStoreInfo: true)
            
            managers[lineid] = manager
        }
        
        return manager
    }
    
    func getPicturePath(picstr:String) -> String? {
        
        guard let task = picManager.download(picstr) else { return nil }
        
        if task.status == .completed {
            
            let path = "\(picManager.cache.downloadFilePath)/\(task.fileName)";
            
            return path
        }
        
        return nil;
    }
    
    func getRecordPath(lineid:String,playpath:String? = nil) -> String? {
        
        let manager = loadManager(lineid: lineid)
        
        if let playpath = playpath {
            
            if let task = manager.fetchTask(playpath), task.status == .completed {
                
                let path = "\(manager.cache.downloadFilePath)/\(task.fileName)";
                
                return path
            }
        }
        
        return nil
    }
    
    func hasTappedDownload(lineid:String) -> Line? {
        
        guard let lineData = UserDefaults.standard.data(forKey: lineid) else {
            
            return nil
        }
        
        let decoder = JSONDecoder()
        let line = try? decoder.decode(Line.self, from: lineData)
        
        return line
    }
    
    func hasTappedDownload(lineid:String,playpath:String) -> Record? {
        
        guard let recordData = UserDefaults.standard.data(forKey: playpath) else {
            
            return nil
        }
        
        let decoder = JSONDecoder()
        let record = try? decoder.decode(Record.self, from: recordData)
        
        return record
    }
    
    func downloadStatus(lineid:String,playpath:String? = nil) -> TRStatus {
        
        let manager = loadManager(lineid: lineid)
        
        if let playpath = playpath {
            
            let task = manager.fetchTask(playpath)
            
            return task?.status ?? .waiting
        }
        
        
        return manager.status
        
    }
    
    func progress(lineid:String,playpath:String? = nil,pblock:@escaping ProgressBlock) {
        
        
        DispatchQueue.global().async {
            
            let manager = self.loadManager(lineid: lineid)
            
            if let playpath = playpath {
                
                let task = manager.fetchTask(playpath)
                
                
                let progress = task?.progress.fractionCompleted ?? 0
                
                if progress >= 1.0 {
                    
                    DispatchQueue.main.async {
                        
                        pblock(true,true,1)
                    }
                    return
                }
                
                DispatchQueue.main.async {
                    
                    pblock(false,false,progress)
                }
                
                
                task?.progress({ task in
                    
                    let progress = task.progress.fractionCompleted
                    
                    if progress >= 1.0 {
                        
                        DispatchQueue.main.async {
                            pblock(true,true,1)
                        }
                        
                        return
                    }
                    
                    DispatchQueue.main.async {
                        pblock(false,false,progress)
                    }
                    
                }).success({ task in
                    
                    DispatchQueue.main.async {
                        pblock(true,true,1)
                    }
                    
                }).failure({ task in
                    
                    DispatchQueue.main.async {
                        pblock(true,false,1)
                    }
                })
                
            } else {
                
                let progress = Double(manager.completedTasks.count) / Double(manager.tasks.count)
                
                if progress >= 1.0 {
                    DispatchQueue.main.async {
                        pblock(true,true,1)
                    }
                    return
                }
                DispatchQueue.main.async {
                    pblock(false,false,progress)
                }
                
                manager.progress { manager in
                    
                    let progress = Double(manager.completedTasks.count) / Double(manager.tasks.count)
                    
                    if progress >= 1.0 {
                        DispatchQueue.main.async {
                            pblock(true,true,1)
                        }
                        return
                    }
                    DispatchQueue.main.async {
                        pblock(false,false,progress)
                    }
                    
                    }.success { manager in
                        DispatchQueue.main.async {
                            pblock(true,true,1)
                        }
                    }.failure { manager in
                        DispatchQueue.main.async {
                            pblock(true,false,1)
                        }
                }
            }
        }
    }
    
    func startLineDown(line:Line,single record:Record? = nil) {
        
        DispatchQueue.global().async {
            
            let manager = self.loadManager(lineid: line.lineid!)
            
            if line.bought == false {
                
                return
            }
            
            let encoder = JSONEncoder()
            if let record = record {
                
                manager.download(record.playpath!)
                
                self.picManager.multiDownload(record.pictureArray!)
                
                if let data = try? encoder.encode(record) {
                    
                    UserDefaults.standard.set(data, forKey: record.playpath!)
                    UserDefaults.standard.synchronize()
                }
                
            } else {
                
                if manager.status == .running {
                    
                    return
                }
                
                manager.multiDownload((line.records?.filter({$0.playpath != nil}).compactMap({$0.playpath!}))!)
                
                var pics:[String] = [];
                
                line.records?.forEach({ record in
                    
                    pics += record.pictureArray!
                })
                
                self.picManager.multiDownload(pics)
                
                if let data = try? encoder.encode(line) {
                    
                    UserDefaults.standard.set(data, forKey: line.lineid!)
                    UserDefaults.standard.synchronize()
                }
            }
        }
    }
    
    func pauseLineDown(line:Line,single record:Record? = nil) {
        
        let manager = self.loadManager(lineid: line.lineid!)
        
        if let record = record {
            
            manager.suspend(record.playpath!)
            
        } else {
            
            manager.totalSuspend()
        }
    }
    
    func removeLineDown(line:Line,single record:Record? = nil) {
        
        let manager = self.loadManager(lineid: line.lineid!)
        
        if let record = record {
            
            manager.remove(record.playpath!)
            
            UserDefaults.standard.removeObject(forKey: record.playpath!)
            UserDefaults.standard.synchronize()
            
            for str in record.pictureArray! {
                
                self.picManager.remove(str)
            }
            
        } else {
            
            manager.totalRemove()
            
            UserDefaults.standard.removeObject(forKey: line.lineid!)
            UserDefaults.standard.synchronize()
            
            var pics:[String] = [];
            
            line.records?.forEach({ record in
                
                pics += record.pictureArray!
            })
            
            for str in pics {
                
                self.picManager.remove(str)
            }
        }
    }
}

